{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "018b80e1",
   "metadata": {},
   "source": [
    "# scipy fslove\n",
    "1. 用于解决多元非线性方程组\n",
    "2. <font color=maroon><b>注意：</b></font> python自带函数以及numpy中的函数都是ufunc，也就是能够在矩阵中进行广播运算\n",
    "\n",
    "## ideas\n",
    "1. 移项法表示成为$f(x_0,x_1,\\cdots,x_n)=0$形式\n",
    "2. 为方程求解设置一个初始值，因为非线性方程不只有一个接，需要从该初始值出发找到一个局部最优解\n",
    "3. 判断fsolve解是否是方程组最优解，可以使用np.isclose(listA,listB)来判断是否是解\n",
    "\n",
    "## usage\n",
    "scipy.optimize.fsolve\n",
    "\n",
    "```\n",
    "fsolve(\n",
    "    func,\n",
    "    x0,\n",
    "    args=(),\n",
    "    fprime=None,\n",
    "    full_output=0,\n",
    "    col_deriv=0,\n",
    "    xtol=1.49012e-08,\n",
    "    maxfev=0,\n",
    "    band=None,\n",
    "    epsfcn=None,\n",
    "    factor=100,\n",
    "    diag=None,\n",
    ")\n",
    "Docstring:\n",
    "Find the roots of a function.\n",
    "\n",
    "Return the roots of the (non-linear) equations defined by\n",
    "func(x) = 0 given a starting estimate.\n",
    "\n",
    "Parameters\n",
    "----------\n",
    "func : callable f(x, *args)\n",
    "    A function that takes at least one (possibly vector) argument,\n",
    "    and returns a value of the same length.\n",
    "x0 : ndarray\n",
    "    The starting estimate for the roots of ``func(x) = 0``.\n",
    "args : tuple, optional\n",
    "    Any extra arguments to `func`.\n",
    "fprime : callable ``f(x, *args)``, optional\n",
    "    A function to compute the Jacobian of `func` with derivatives\n",
    "    across the rows. By default, the Jacobian will be estimated.\n",
    "full_output : bool, optional\n",
    "    If True, return optional outputs.\n",
    "col_deriv : bool, optional\n",
    "    Specify whether the Jacobian function computes derivatives down\n",
    "    the columns (faster, because there is no transpose operation).\n",
    "xtol : float, optional\n",
    "    The calculation will terminate if the relative error between two\n",
    "    consecutive iterates is at most `xtol`.\n",
    "maxfev : int, optional\n",
    "    The maximum number of calls to the function. If zero, then\n",
    "    ``100*(N+1)`` is the maximum where N is the number of elements\n",
    "    in `x0`.\n",
    "band : tuple, optional\n",
    "    If set to a two-sequence containing the number of sub- and\n",
    "    super-diagonals within the band of the Jacobi matrix, the\n",
    "    Jacobi matrix is considered banded (only for ``fprime=None``).\n",
    "epsfcn : float, optional\n",
    "    A suitable step length for the forward-difference\n",
    "    approximation of the Jacobian (for ``fprime=None``). If\n",
    "    `epsfcn` is less than the machine precision, it is assumed\n",
    "    that the relative errors in the functions are of the order of\n",
    "    the machine precision.\n",
    "factor : float, optional\n",
    "    A parameter determining the initial step bound\n",
    "    (``factor * || diag * x||``). Should be in the interval\n",
    "    ``(0.1, 100)``.\n",
    "diag : sequence, optional\n",
    "    N positive entries that serve as a scale factors for the\n",
    "    variables.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86e8ef2b",
   "metadata": {},
   "source": [
    "## sample1\n",
    "$$\n",
    "\\left\\{\n",
    "\\begin{array}{ll}\n",
    "    x_0cos(x_1) = 4 \\\\\n",
    "    x_1x_0 - x_1 = 5 \\\\\n",
    "\\end{array}\n",
    "\\right .\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "04d2ff29",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([6.50409711, 0.90841421])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy.optimize import fsolve\n",
    "\n",
    "# parameter of x is a vector with each item symblizes one variable\n",
    "# this function will return the whole equation set with pattern f(x)=0\n",
    "def func(x):\n",
    "    return [x[0]*np.cos(x[1])-4,\n",
    "            x[1]*x[0] - x[1]-5]\n",
    "\n",
    "resx = fsolve(func, [10,1])\n",
    "resx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "43dc7477",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True,  True])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# determine whether this solution is the root\n",
    "np.isclose(func(resx),[0.0,0.0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c0f125bd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[-1.3322676295501878e-14, 1.9539925233402755e-14]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "func(resx)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e0f4536",
   "metadata": {},
   "source": [
    "## sample2\n",
    "$$\n",
    "\\left\\{\n",
    "\\begin{array}{ll}\n",
    "5x_1 = -3 \\\\\n",
    "4{x_0}^2 - 2sin(x_1x_2) = 0 \\\\\n",
    "x_1x_2 = 1.5 \\\\\n",
    "\\end{array}\n",
    "\\right .\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "9afc3f58",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.70622057, -0.6       , -2.5       ])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from math import sin, cos\n",
    "from scipy import optimize\n",
    "\n",
    "def func(x):\n",
    "    x0,x1,x2 = x.tolist()\n",
    "    return [5*x1+3,\n",
    "            4*x0*x0 - 2*sin(x1*x2),\n",
    "            x1*x2 - 1.5]\n",
    "\n",
    "resx = fsolve(func, [1,1,1])\n",
    "resx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "8914cac2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.70622057, -0.6       , -2.5       ])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# we could also use fprime parameter\n",
    "# which is: define jacobian matrix of current equation set\n",
    "def jacobian(x):\n",
    "    x0, x1,x2 = x.tolist()\n",
    "    return [\n",
    "        [0,5,0],\n",
    "        [8*x0, -2*x2*cos(x1*x2),-2*x1*cos(x1*x2)],\n",
    "        [0,x2,x1]\n",
    "    ]\n",
    "\n",
    "resx1 = fsolve(func,[1,1,1], fprime=jacobian)\n",
    "resx1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "c1e61a81",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True,  True,  True])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.isclose(func(resx1),[0.0,0.0,0.0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "a9a0c7e8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0.0, -9.126033262418787e-14, 5.329070518200751e-15]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "func(resx1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "89905842",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
